package com.fm.jbsql.sql;

//import com.sybase.jdbcx.EedInfo;
import java.util.logging.Logger;
import java.sql.*;
import com.sybase.jdbcx.SybMessageHandler;
import com.sybase.jdbc3.jdbc.SybSQLException;
import com.sybase.jdbc3.jdbc.SybSQLWarning;
import com.sybase.jdbc3.jdbc.SybConnection;
import com.sybase.jdbcx.EedInfo;

/**
 * Created by IntelliJ IDEA.
 * User: syaroshenko
 * Date: Jul 13, 2006
 * Time: 11:36:27 AM
 * Sybase implementation of driver specifics. Based on http://jtds.sourceforge.net.
 */

/**
 * Sybase implementation of driver specifics. Based on http://jtds.sourceforge.net.
 */
public final class DbDriverSybase extends DbDriver implements SybMessageHandler{
    private static final Logger logger = Logger.getLogger("com.fm.jbsql.sql.DbDriverSybase");
    
    //sybase message handler:
	public SQLException messageHandler(SQLException sqe) {
		String msg="";
		String proc="";
		int line=0;
		int code = sqe.getErrorCode();
		String state=sqe.getSQLState();
		
		if(sqe instanceof EedInfo ){
			proc=((EedInfo)sqe).getProcedureName();
			line=((EedInfo)sqe).getLineNumber();
		}
		
		if( ( proc!=null && proc.length()>0 ) || line>0){
			if( proc!=null && proc.length()>0 )msg+=proc;
			else msg+="<sql>";
			
			if( line>0 )msg+=" ("+line+"):";
			else msg+=":";
					
			msg+=" "+sqe.getMessage();
			
			StackTraceElement[] ste=sqe.getStackTrace();
			if(sqe instanceof SQLWarning){
				sqe=new SQLWarning(msg,state,code);
			}else{
				sqe=new SQLException(msg,state,code);
			}
			sqe.setStackTrace(ste);
		}
		
		if(sqe instanceof SQLWarning){
			this.checkForWarning( sqe );
			return null;
		}
		return sqe;
	}
	

    /**
     */
    public SQLScriptCompiler getCompiler(){
    	return new SQLScriptCompilerJConnect();
    }
    
    /**
     * Formatted JDBC class string.
     * @return String
     */
    public String getJdbcClass() {
        //return "net.sourceforge.jtds.jdbc.Driver";
        return "com.sybase.jdbc3.jdbc.SybDriver";
        //return "com.sybase.jdbc2.jdbc.SybDriver";
    }

    /**
     * Formatted driver URL.
     * @return String
     */
    public String getJdbcDriver() {
        return "jdbc:sybase:Tds";
        //return "jdbc:jtds:sybase";
    }

    /**
     * Formatted connection URL.
     * @param servername Server name
     * @param db Database name
     * @return String
     */
    public String getConnectionString(final String servername, final String db){
        return getJdbcDriver() + ":"+servername+"/"+db;
        //return getJdbcDriver() + "://"+servername+"/"+db;
    }

    /**
     * Driver-dependent table statement.
     * @param isTemp temporary table flag
     * @param checkExisting check existing clause
     * @param tablename table name
     * @param col_array columns array {"name", "nullable", "collation"}
     * @return String
     */
    public String getCreateTableStmt(boolean isTemp, boolean checkExisting, String tablename, String col_array[][]) {
        String columns = "";
        if ( col_array != null ) {
            int len = col_array.length;
            for (int idx = 0; idx < len; idx++) columns += col_array[idx][0] + " " + col_array[idx][1] + (idx < len-1 ? ", " : "");
        }
        return (checkExisting ? "if object_id('"+ (isTemp? "#" : "") + tablename + "') is null ":"") + (isTemp? "" : "execute('") + "create table " + (isTemp? "#" : "") + tablename + " (" + columns + ")" + (isTemp? "" : "')");
    }

    /**
     * Driver-dependent temporary table symbol.
     * @return String
     */
    public String tempTableSymbol() {
        return "#";
    }

    /**
     * Driver-dependent temporary current date statement.
     * @return String
     */
    public String getDateStmt() {
        return "getdate()";
    }

    /**
     * Driver-dependent commands terminator.
     * @return String
     */
    public String getCmdTerminator() {
        return "go";
    }

    /**
     * Initialize connection: run sybase specific code to disable quoted identifiers.
     * @param conn Connection
     * @throws NullPointerException
     * @throws SQLException
     */
    public void initConnection(final Connection conn) throws NullPointerException, SQLException {
        if ( conn == null ) throw new NullPointerException();
       	((SybConnection)conn).setSybMessageHandler(this);

        // reset quoted identifier
        Statement stmt = conn.createStatement();
        logger.info("Executing query 'set quoted_identifier off' ");
        stmt.executeUpdate("set quoted_identifier off");
        this.checkForWarning(stmt);
        logger.info("done.");
    }

    /**
     * Return "code before" statement
     * @return String
     */
    public final String getCodeBeforeStart() {
        return "*CODE Before";
    }

    /**
     * Return "code after" statement
     * @return String
     */
    public final String getCodeAfterStart() {
        return "*CODE After";
    }

    /**
     * Return "code end" statement
     * @return String
     */
    public final String getCodeEnd() {
        return "*";
    }

     /**
     * verifies if string is a reserved token
     * @return String
     */
    public int getReservedToken(final String str) {
        if ( str.startsWith(this.getCodeBeforeStart()) ) return ETokenType.ETT_CODE_BEFORE_START;
        if ( str.startsWith(this.getCodeAfterStart()) ) return ETokenType.ETT_CODE_AFTER_START;
        if ( str.startsWith(this.getCodeEnd()) ) return ETokenType.ETT_CODE_END;
        if ( this.getCmdTerminator() == null || str.equalsIgnoreCase(this.getCmdTerminator()) ) return ETokenType.ETT_TERMINATOR;
        return ETokenType.ETT_NONE;
    }

    /**
    * returns value of sybase variable @@trancount
    * @return String
    */
    public long getTranCount(final Connection conn) {
        Statement stmt;
        ResultSet rs;
        int trancount = 0;
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery("select @@trancount as trancount");
            rs.next();
            trancount = rs.getInt(1);
            stmt.close();
        }
        catch(SQLException ex) {
            ex.printStackTrace();
        }
        return trancount;
    }
}
